module ew {
    export class Vector3 {
        public x: number;
        public y: number;
        public z: number;

        public static zero = new Vector3(0, 0, 0);
        public static right = new Vector3(1, 0, 0);
        public static left = new Vector3(-1, 0, 0);
        public static up = new Vector3(0, 1, 0);
        public static down = new Vector3(0, -1, 0);
        public static forward = new Vector3(0, 1, 0);
        public static backward = new Vector3(0, -1, 0);

        constructor(x: number, y: number, z: number) {
            this.x = x ? x : 0;
            this.y = y ? y : 0;
            this.z = z ? z : 0;
        }

        //Non statics

        public getLengthSquared(): number {
            return this.x * this.x + this.y * this.y + this.z * this.z;
        }

        public getLength(): number {
            return Math.sqrt(this.getLengthSquared());
        }

        public negate(): Vector3 {
            var negated = new Vector3(-this.x, -this.y, -this.z);
            return negated;
        }

        public add(vector: Vector3): Vector3 {
            var sum = new Vector3(this.x + vector.x, this.y + vector.y, this.z + vector.z);
            return sum;
        }

        public substract(vector: Vector3): Vector3 {
            var difference = new Vector3(this.x - vector.x, this.y - vector.y, this.z - vector.z);
            return difference;
        }

        public multiply(scalar: number): Vector3 {
            var product = new Vector3(this.x * scalar, this.y * scalar, this.z * scalar);
            return product;
        }
        
        public divide(scalar: number): Vector3 {
            var quotient = new Vector3(this.x / scalar, this.y / scalar, this.z / scalar);
            return quotient;
        }

        public normalize(): Vector3 {
            var length = this.getLength();
            var normalized = new Vector3(this.x / length, this.y / length, this.z / length);
            return normalized;
        }

        public distanceTo(vector: Vector3): number {
            return this.substract(vector).getLength();
        }

        public distanceSquaredTo(vector: Vector3): number {
            return this.substract(vector).getLengthSquared();
        }

        public dot(vector: Vector3): number {
            var product = this.x * vector.x + this.y * vector.y + this.z * vector.z;
            return product;
        }

        public cross(vector: Vector3): Vector3 {
            //Sauruss' rule
            var product = new Vector3(0, 0, 0);
            product.x = this.y * vector.z - this.z * vector.y;
            product.y = this.z * vector.x - this.x * vector.z;
            product.z = this.x * vector.y - this.y * vector.x;

            return product; 
        }

        public static lerp(vector1: Vector3, vector2: Vector3, amount: number): Vector3 {
            var lerped = new Vector3(vector1.x, vector1.y, vector1.z);
            lerped.x += (vector2.x - vector1.x) * amount;
            lerped.y += (vector2.z - vector1.z) * amount;
            lerped.z += (vector2.z - vector1.z) * amount;
            return lerped;
        }
    }
}